﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace WindowsGame1
{
    public class GravityBox
    {
        Rectangle gravBox;
        Vector2 gravity;

        public GravityBox()
        {
            gravBox = new Rectangle();
            gravity = new Vector2();
        }

        public GravityBox(Rectangle newGravBox, Vector2 newGravity)
        {
            gravBox = newGravBox;
            gravity = newGravity;
        }

        public Rectangle getGravbox()
        {
            return gravBox;
        }

        public Vector2 getGravity()
        {
            return gravity;
        }

        public Vector2 getPosition()
        {
            return new Vector2(gravBox.X, gravBox.Y);
        }

        public Vector2 getSize()
        {
            return new Vector2(gravBox.Width, gravBox.Height);
        }
    }

    public class Line
    {
        //bool isCurved;

        //Curve lineCurve;

        Vector2 v1;
        Vector2 v2;
        float angle;
        float length;

        float restitution;
        bool deletable;

        public Line(float res)
        {
            v1 = Vector2.Zero;
            v2 = Vector2.Zero;
            angle = 0.0f;
            length = 0.0f;
            calc();
            restitution = res;
        }

        public Line(Vector2 vin1, Vector2 vin2, float res)
        {
            v1 = vin1;
            v2 = vin2;
            calc();
            restitution = res;
        }

        public Line(float vin1x, float vin1y, float vin2x, float vin2y, float res)
        {
            v1 = new Vector2(vin1x, vin1y);
            v2 = new Vector2(vin2x, vin2y);
            calc();
            restitution = res;
        }

        public void setPosition(Vector2 vin1, Vector2 vin2)
        {
            v1 = vin1;
            v2 = vin2;
            calc();
        }

        public void setPosition(float vin1x, float vin1y, float vin2x, float vin2y)
        {
            v1.X = vin1x;
            v1.Y = vin1y;
            v2.X = vin2x;
            v2.Y = vin2y;
            calc();
        }

        public void setRestitution(float res)
        {
            restitution = res;
        }

        public Vector2 getVert1()
        {
            return v1;
        }

        public Vector2 getVert2()
        {
            return v2;
        }

        public float getAngle()
        {
            return angle;
        }

        public float getRestitution()
        {
            return restitution;
        }

        public float getLength()
        {
            return length;
        }

        public void setDelete(bool set)
        {
            deletable = set;
        }

        public bool getDelete()
        {
            return deletable;
        }

        public Vector2 getDirectionalVector()
        {
            return Vector2.Normalize(Vector2.Subtract(v2, v1));
        }

        public Vector2 getNormalVector()
        {
            return Vector2.Normalize(new Vector2(-getDirectionalVector().Y, getDirectionalVector().X));
        }

        //Returns the distance to the line segment from a point
        public float getDistanceTo(float ptx, float pty)
        {
            //Angles to line from v1 to pt, line itself, and line to line from v1 to pt
            double beta = Math.Atan((pty - v1.Y) / (ptx - v1.X));
            double theta = Math.Abs(beta - angle);

            double precalc = Math.Sqrt(Math.Pow(v1.Y - pty, 2) + Math.Pow(v1.X - ptx, 2));
            float dist = (float)(precalc * Math.Sin(theta));

            float lpos = (float)(precalc * Math.Cos(theta));

            //Adjust distance if point is off line ends
            //(dist would be measured to nonexistent extension of the line)

            if (ptx < v1.X)
            {
                dist = (float)precalc;
                //Console.WriteLine("<0");
            }
            else if (ptx > v2.X)
            {
                dist = (float)Math.Sqrt(Math.Pow(v2.Y - pty, 2) + Math.Pow(v2.X - ptx, 2));
                //Console.WriteLine(">len");
            }

            return Math.Abs(dist);
        }

        private void calc()
        {
            angle = (float)Math.Atan2(v2.Y - v1.Y, v2.X - v1.X);
            length = Vector2.Distance(v1, v2);
        }
    }


    public class Ball
    {
        Vector2 velocity;
        Vector2 position;
        Vector2 startposition;
        bool froze;
        float radius;

        public Ball()
        {
            velocity = Vector2.Zero;
            position = Vector2.Zero;
        }

        public Ball(Vector2 pos, float rad)
        {
            velocity = Vector2.Zero;
            position = pos;
            radius = rad;
        }

        public Ball(float posx, float posy, float rad)
        {
            velocity = Vector2.Zero;
            position = new Vector2(posx, posy);
            radius = rad;
        }

        public Vector2 getPosition()
        {
            return position;
        }

        public Vector2 getVelocity()
        {
            return velocity;
        }

        public float getRadius()
        {
            return radius;
        }

        public Vector2 getStartPosition()
        {
            return startposition;
        }

        public void setPosition(float inx, float iny)
        {
            position.X = inx;
            position.Y = iny;
        }

        public void setPosition(Vector2 invec)
        {
            position = invec;
        }

        public void setRadius(float rad)
        {
            radius = rad;
        }

        public void setStartPosition(Vector2 sp)
        {
            startposition = sp;
        }

        public void bounce(Line bline)
        {
            velocity = Vector2.Multiply(Vector2.Reflect(velocity, bline.getNormalVector()), bline.getRestitution());
        }

        public void accelerate(Vector2 accel, float gameTime)
        {
            velocity += accel * gameTime;
        }

        public void move(float gameTime)
        {
            position += velocity * gameTime;
        }

        public void moveBack(float gameTime)
        {
            position -= velocity * gameTime;
        }

        public void setVelocity(Vector2 vel)
        {
            velocity = vel;
        }

        public void setVelocity(float velx, float vely)
        {
            velocity.X = velx;
            velocity.Y = vely;
        }

        public void freeze(bool frz)
        {
            froze = frz;
        }

        public bool frozen()
        {
            return froze;
        }
    }

    public class Goal
    {
        Vector2 position;
        float radius;

        public Goal(float rad)
        {
            position = new Vector2(0.0f, 0.0f);
            radius = rad;
        }

        public Goal(Vector2 pos, float rad)
        {
            position = pos;
            radius = rad;
        }

        public Goal(float posx, float posy, float rad)
        {
            position = new Vector2(posx, posy);
            radius = rad;
        }

        public void setPosition(Vector2 pos)
        {
            position = pos;
        }

        public void setPosition(float posx, float posy)
        {
            position.X = posx;
            position.Y = posy;
        }

        public void setRadius(float rad)
        {
            radius = rad;
        }

        public Vector2 getPosition()
        {
            return position;
        }

        public float getRadius()
        {
            return radius;
        }

        public Boolean ballIn(Ball ball)
        {
            return Vector2.Distance(ball.getPosition(), position) < ball.getRadius() + radius;
        }
    }
}
